// Octopod (Controls Transfer of Pieces of Data)
// Copyright (c) 2005-2010 Barath Raghavan and James Wilcox.  All rights reserved.
//
// GPL goes here
//
// Convenient access to configuration data.

#ifndef OCTOPOD_CONFIG_H__
#define OCTOPOD_CONFIG_H__

#include <QtCore>

#include "sharelist.pb.h"
#include "userlist.pb.h"

namespace octopod {

class config {
 public:
  // Gets the list of all directories which are shares and places it in sharedirs.
  // Caller is responsible for allocating and deleting memory of sharedirs; NULL 
  // is not accepted.
  // This function is threadsafe.
  // Returns 0 if at least on share was found, -1 otherwise.
  static int GetShareDirs(ShareList *sharedirs);

  // Adds a new share to the list. The path must be clean, as determined by
  // IsClean(path).
  // This function is threadsafe.
  // Returns 0 on success, -1 on failure.
  static int AddShareDir(const QString &path);

  // Returns true if path contains only characters which we allow.
  // A clean path must be both cross platform and secure.
  static bool IsClean(const QString &path) {
    return true;
  }

  // Gets the list of all users we've ever heard of. The users come as (id,
  // pubkey) pairs.
  // Caller is responsible for allocating and deleting memory for the list.
  // NULL is not accepted.
  // This function is threadsafe.
  // Returns 0 if at least on user was found, -1 otherwise.
  static int GetUsers(UserList *users);

  // Adds a new user to the list. The user must have an ascii id and a properly
  // encoded public key.
  // This function is threadsafe.
  // Returns 0 on succes, -1 on failure.
  static int AddUser(const std::string &id, const std::string &key);

  // Searches the local list of users to see if we know their public key.
  // If you just want the public key, just call the key() member function on the
  // returned pointer. (Remember to check for NULL first.)
  // This function is threadsafe.
  // Returns NULL on failure.
  static const User *FindUserByID(const std::string &id);


  static const char *kConfigDir;
  static const char *kKeysFile;
  static const char *kSharesFile;

 private:
  static QReadWriteLock shareslock_;
  static QReadWriteLock keyslock_;

  // Opens the given path relative to the users config directory.
  // Given path must be clean.
  // Caller must close and delete file.
  // This function is not thread-safe. Necessary locking must be performed by caller.
  // Returns NULL on error.
  static QFile *OpenLocalConfig(const QString& name, QIODevice::OpenMode mode);

  // Reads the given config file and places all of the resulting data
  // into buf.
  // Caller is responsible for allocating and deleting buf. NULL is not accepted
  // for buf or lock.
  // This function is threadsafe.
  // Returns 0 on success, -1 on error.
  //
  // Together with WriteLocalConfig, this function abstracts the filesystem from
  // the caller. It is not responsible for parsing the data.
  static int ReadLocalConfig(const QString &name, QByteArray *buf,
                             QReadWriteLock *lock);

  // Writes the contents of the given string to the given config file.
  // NULL is not accepted for lock.
  // This function is threadsafe.
  // Returns 0 on success, -1 on error.
  //
  // The asymmetry between the interfaces of ReadLocalConfig and WriteLocalConfig
  // allows the caller to perform minimal data conversion. So although it is not
  // responsible for data parsing, it does attempt to simplify it.
  static int WriteLocalConfig(const QString &name, const std::string &buf,
                              QReadWriteLock *lock);

  // Reads in a text-formatted protobuf from file, parses it, and places results
  // in given *msg.
  // NULL is not accepted for msg or lock.
  // This function is threadsafe.
  // Returns 0 on success, -1 on error.
  static int ParseMessageFromFile(const QString &file,
                                  google::protobuf::Message *msg,
                                  QReadWriteLock *lock);

  // Writes out the given message to a file, printing it as text-format.
  // NULL is not accepted for msg or lock.
  // This function is threadsafe.
  // Returns 0 on success, -1 on error.
  static int PrintMessageToFile(const QString &file,
                                const google::protobuf::Message *msg,
                                QReadWriteLock *lock);
};

const char* config::kConfigDir = ".octopod"; // our spot in QDir::home()
const char* config::kSharesFile = "shares"; // name of list of shares
const char* config::kKeysFile = "keys"; // name of list of users' keys

// locks for the config files
QReadWriteLock config::shareslock_;
QReadWriteLock config::keyslock_;

} // namespace octopod

#endif //OCTOPOD_CONFIG_H__
